home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / Mac OS X Throbber / Source / Utilities / PPDebug_New.cp next >
Encoding:
Text File  |  2000-06-24  |  13.7 KB  |  458 lines

  1. // ===========================================================================
  2. //    PPDebug_New.cp        ©1997-1999 Metrowerks Inc. All rights reserved
  3. //    Original Author: John C. Daub
  4. // ===========================================================================
  5. //    Overrides for C++ memory allocation mechanisms, to work better with
  6. //    PowerPlant. Includes use of DebugNew and Spotlight as well (via the
  7. //    Debugging Classes).
  8. //
  9. //    Contains support for: new, new[], new(nothrow), new[](nothrow), delete,
  10. //    and delete[]. Also contains support for the DebugNew versions of new
  11. //    that take file and line arguments. A new_handler implementation is
  12. //    provided as well.
  13.  
  14. #include <PP_Debug.h>
  15. #include <UOnyx.h>
  16.  
  17. #include "UMiscUtils.h"
  18.  
  19.  
  20. // ===========================================================================
  21. //    • MW standard operator new configuration
  22. // ===========================================================================
  23.  
  24. #undef new
  25. #include <new>
  26.  
  27.     // NEWMODE_MALLOC seems to be the fastest allocator. Furthermore
  28.     // using the MSL's malloc as the ultimate allocator allows you to
  29.     // browse your new (malloc) heaps in ZoneRanger 2.x
  30. #undef NEWMODE
  31. #define NEWMODE NEWMODE_MALLOC
  32.  
  33. #define OPERATOR_NEW            _std_operator_new
  34. #define OPERATOR_DELETE            _std_operator_delete
  35. #define OPERATOR_ARRAY_NEW        _std_operator_array_new
  36. #define OPERATOR_ARRAY_DELETE    _std_operator_array_delete
  37.  
  38. void* _std_operator_new(PP_STD::size_t size) throw(PP_STD::bad_alloc);
  39. void* _std_operator_new(PP_STD::size_t size, const PP_STD::nothrow_t&) throw();
  40. void _std_operator_delete(void* ptr) throw();
  41.  
  42. void *_std_operator_array_new(PP_STD::size_t size) throw(PP_STD::bad_alloc);
  43. void *_std_operator_array_new(PP_STD::size_t size,const PP_STD::nothrow_t&) throw();
  44. void _std_operator_array_delete(void *ptr) throw();
  45.  
  46.  
  47. // ===========================================================================
  48. //    • DebugNew configuration
  49. // ===========================================================================
  50.  
  51. // this will generate some linker warnings about multiple definitions
  52. // (between this and the MSL runtime libraries). FYI, the MW Linkers always
  53. // use what they find first in the "Link Order" (or Segments) page of the
  54. // project window.. top to bottom. However, regardless of order, the MW
  55. // Linkers ALAWYS take source over libraries if they find duplicates.
  56.  
  57. #if PP_Debug && PP_DebugNew_Support
  58.     #define DEBUG_NEW_NO_GLOBAL_OPERATORS 1        // suppress DebugNew's global
  59.                                                 // new/delete operators
  60.     #include "DebugNew.cp"
  61. #else
  62.     #include "New.cp"
  63. #endif
  64.  
  65. typedef void* (*_op_new)(PP_STD::size_t);
  66. typedef void* (*_op_new_nothrow)(PP_STD::size_t, const PP_STD::nothrow_t&);
  67.  
  68.  
  69. // ===========================================================================
  70.  
  71.  
  72. // ---------------------------------------------------------------------------
  73. //    • AllowAllocation                                [static]
  74. // ---------------------------------------------------------------------------
  75. //    Determines if it's ok to allocate memory or not. Typical use would
  76. //    be to check the GrowZone, check for critical sections, etc. Returns
  77. //    true if it's ok to proceed with the allocation.
  78.  
  79. static bool    AllowAllocation();
  80.  
  81. static bool
  82. AllowAllocation()
  83. {
  84.     return ((UMiscUtils::MemoryIsLow() == false)
  85.             && (StCriticalSection::InCriticalSection() == false)
  86.             && (StInterruptSection::InInterruptSection() == false));
  87. }
  88.  
  89.  
  90. #pragma mark -
  91. #pragma mark === operator new ===
  92.  
  93. // ---------------------------------------------------------------------------
  94. //    • operator new(size_t) throw(bad_alloc)
  95. // ---------------------------------------------------------------------------
  96. //    Overriden to test for low-memory conditions.
  97.  
  98. void*
  99. operator new(
  100.     PP_STD::size_t    size) throw (PP_STD::bad_alloc)
  101. {
  102.     StSpotlightDisable_();
  103.     
  104.     void* ptr = nil;
  105.     if (AllowAllocation()) {
  106.     
  107.         // The allocation function should throw std::bad_alloc if
  108.         // there's a failure, so no need for us to handle that here...just
  109.         // let it propagate normally.
  110.         
  111.     #if PP_Debug && PP_DebugNew_Support && (DEBUG_NEW >= DEBUG_NEW_BASIC)
  112.         ptr = DebugNewDoAllocate(size, 0, 0, (_op_new)_std_operator_new, false);
  113.     #else
  114.         ptr = _std_operator_new(size);
  115.     #endif
  116.     }
  117.  
  118.     return ptr;
  119. }
  120.  
  121.  
  122. // ---------------------------------------------------------------------------
  123. //    • operator new(size_t, nothrow_t&) throw()
  124. // ---------------------------------------------------------------------------
  125. //    Overriden to test for low-memory conditions.
  126.  
  127. void*
  128. operator new(
  129.     PP_STD::size_t                size,
  130.     const PP_STD::nothrow_t&     nt) throw ()
  131. {
  132. #pragma unused(nt)    // Keeps the compiler quiet
  133.  
  134.     StSpotlightDisable_();
  135.     
  136.     void* ptr = nil;
  137.     if (AllowAllocation()) {
  138.  
  139.     #if PP_Debug && PP_DebugNew_Support && (DEBUG_NEW >= DEBUG_NEW_BASIC)
  140.         ptr = DebugNewDoAllocate(size, 0, 0, (_op_new_nothrow)_std_operator_new, false);
  141.     #else
  142.         ptr = _std_operator_new(size, nt);
  143.     #endif
  144.     }
  145.     
  146.     return ptr;
  147. }
  148.  
  149.  
  150. // ---------------------------------------------------------------------------
  151. //    • operator new[](size_t) throw(bad_alloc)
  152. // ---------------------------------------------------------------------------
  153. //    Overriden to test for low-memory conditions.
  154.  
  155. void*
  156. operator new[](
  157.     PP_STD::size_t    size) throw (PP_STD::bad_alloc)
  158. {
  159.     StSpotlightDisable_();
  160.     
  161.     void* ptr = nil;
  162.     if (AllowAllocation()) {
  163.     
  164.         // The allocation function should throw std::bad_alloc if
  165.         // there's a failure, so no need for us to handle that here...just
  166.         // let it propagate normally.
  167.         
  168.     #if PP_Debug && PP_DebugNew_Support && (DEBUG_NEW >= DEBUG_NEW_BASIC)
  169.         ptr = DebugNewDoAllocate(size, 0, 0, (_op_new)_std_operator_array_new, true);
  170.     #else
  171.         ptr = _std_operator_array_new(size);
  172.     #endif
  173.     }
  174.     
  175.     return ptr;
  176. }
  177.  
  178.  
  179. // ---------------------------------------------------------------------------
  180. //    • operator new[](size_t, nothrow_t&) throw()
  181. // ---------------------------------------------------------------------------
  182. //    Overriden to test for low-memory conditions.
  183.  
  184. void*
  185. operator new[](
  186.     PP_STD::size_t                size,
  187.     const PP_STD::nothrow_t&    nt) throw ()
  188. {
  189. #pragma unused(nt)    // Keeps the compiler quiet
  190.  
  191.     StSpotlightDisable_();
  192.     
  193.     void* ptr = nil;
  194.     if (AllowAllocation()) {
  195.  
  196.     #if PP_Debug && PP_DebugNew_Support && (DEBUG_NEW >= DEBUG_NEW_BASIC)
  197.         ptr = DebugNewDoAllocate(size, 0, 0, (_op_new_nothrow)_std_operator_array_new, true);
  198.     #else
  199.         ptr = _std_operator_array_new(size, nt);
  200.     #endif
  201.     }
  202.     
  203.     return ptr;
  204. }
  205.  
  206.  
  207. #pragma mark === leaks new ===
  208.  
  209. #if PP_Debug && PP_DebugNew_Support && (DEBUG_NEW == DEBUG_NEW_LEAKS)
  210.  
  211. // Prototypes
  212. void*    operator new(PP_STD::size_t size, const char* file, int line) throw(PP_STD::bad_alloc);
  213. void*    operator new(PP_STD::size_t size, const PP_STD::nothrow_t& nt, const char* file, int line) throw();
  214. void*    operator new[](PP_STD::size_t size, const char* file, int line) throw (PP_STD::bad_alloc);
  215. void*    operator new[](PP_STD::size_t size, const PP_STD::nothrow_t& nt, const char* file, int line) throw ();
  216.  
  217.  
  218. // ---------------------------------------------------------------------------
  219. //    • operator new(size_t, char*, int) throw(bad_alloc)
  220. // ---------------------------------------------------------------------------
  221. //    Only used when DebugNew is active. Same as new(size_t) but records
  222. //    the location of the allocation.
  223.  
  224. void*
  225. operator new(
  226.     PP_STD::size_t        size,
  227.     const char*            file,
  228.     int                    line) throw (PP_STD::bad_alloc)
  229. {
  230. #pragma unused (file, line)    // Quiet down the non-debug builds.
  231.  
  232.     StSpotlightDisable_();
  233.     
  234.     void* ptr = nil;
  235.     if (AllowAllocation()) {
  236.         
  237.         // The allocation function should throw std::bad_alloc if
  238.         // there's a failure, so no need for us to handle that here...just
  239.         // let it propagate normally.
  240.         
  241.     #if PP_Debug && PP_DebugNew_Support && (DEBUG_NEW >= DEBUG_NEW_BASIC)
  242.         ptr = DebugNewDoAllocate(size, file, line, (_op_new)_std_operator_new, false);
  243.     #else
  244.         ptr = _std_operator_new(size);
  245.     #endif
  246.     }
  247.     
  248.     return ptr;
  249. }
  250.  
  251.  
  252. // ---------------------------------------------------------------------------
  253. //    • operator new(size_t, char*, int) throw()
  254. // ---------------------------------------------------------------------------
  255. //    Only used when DebugNew is active. Same as new(size_t) nothrow but records
  256. //    the location of the allocation. You'll need to use the DebugNew NEW_NOTHROW
  257. //    macro to invoke this method (instead of the usual NEW). See DebugNew.h
  258. //    for more information.
  259.  
  260. void*
  261. operator new(
  262.     PP_STD::size_t                size,
  263.     const PP_STD::nothrow_t&    nt,
  264.     const char*                    file,
  265.     int                            line) throw ()
  266. {
  267. #pragma unused (nt, file, line)    // Quiet down the non-debug builds.
  268.  
  269.     StSpotlightDisable_();
  270.     
  271.     void* ptr = nil;
  272.     if (AllowAllocation()) {
  273.     
  274.         // The allocation function should throw std::bad_alloc if
  275.         // there's a failure, so no need for us to handle that here...just
  276.         // let it propagate normally.
  277.         
  278.     #if PP_Debug && PP_DebugNew_Support && (DEBUG_NEW >= DEBUG_NEW_BASIC)
  279.         ptr = DebugNewDoAllocate(size, file, line, (_op_new_nothrow)_std_operator_new, false);
  280.     #else
  281.         ptr = _std_operator_new(size, nt);
  282.     #endif
  283.     }
  284.     
  285.     return ptr;
  286. }
  287.  
  288.  
  289. // ---------------------------------------------------------------------------
  290. //    • operator new[](size_t, char*, int) throw(bad_alloc)
  291. // ---------------------------------------------------------------------------
  292. //    Only used when DebugNew is active. Same as new[](size_t) but records
  293. //    the location of the allocation.
  294.  
  295. void*
  296. operator new[](
  297.     PP_STD::size_t    size,
  298.     const char*        file,
  299.     int                line) throw (PP_STD::bad_alloc)
  300. {
  301. #pragma unused (file, line)    // Quiet down the non-debug builds.
  302.  
  303.     StSpotlightDisable_();
  304.     
  305.     void* ptr = nil;
  306.     if (AllowAllocation()) {
  307.         
  308.         // The allocation function should throw std::bad_alloc if
  309.         // there's a failure, so no need for us to handle that here...just
  310.         // let it propagate normally.
  311.         
  312.     #if PP_Debug && PP_DebugNew_Support && (DEBUG_NEW >= DEBUG_NEW_BASIC)
  313.         ptr = DebugNewDoAllocate(size, file, line, (_op_new)_std_operator_array_new, true);
  314.     #else
  315.         ptr = _std_operator_array_new(size);
  316.     #endif
  317.     }
  318.  
  319.     return ptr;
  320. }
  321.  
  322.  
  323. // ---------------------------------------------------------------------------
  324. //    • operator new[](size_t, char*, int) throw()
  325. // ---------------------------------------------------------------------------
  326. //    Only used when DebugNew is active. Same as new[](size_t) nothrow but records
  327. //    the location of the allocation. You'll need to use the DebugNew NEW_NOTHROW
  328. //    macro to invoke this method (instead of the usual NEW). See DebugNew.h
  329. //    for more information.
  330.  
  331. void*
  332. operator new[](
  333.     PP_STD::size_t                size,
  334.     const PP_STD::nothrow_t&    nt,
  335.     const char*                    file,
  336.     int                            line) throw ()
  337. {
  338. #pragma unused (nt, file, line)    // Quiet down the non-debug builds.
  339.  
  340.     StSpotlightDisable_();
  341.     
  342.     void* ptr = nil;
  343.     if (AllowAllocation()) {
  344.         
  345.         // The allocation function should throw std::bad_alloc if
  346.         // there's a failure, so no need for us to handle that here...just
  347.         // let it propagate normally.
  348.         
  349.     #if PP_Debug && PP_DebugNew_Support && (DEBUG_NEW >= DEBUG_NEW_BASIC)
  350.         ptr = DebugNewDoAllocate(size, file, line, (_op_new_nothrow)_std_operator_array_new, true);
  351.     #else
  352.         ptr = _std_operator_array_new(size, nt);
  353.     #endif
  354.     }
  355.  
  356.     return ptr;
  357. }
  358.  
  359.  
  360. #endif // PP_Debug && PP_DebugNew_Support && (DEBUG_NEW == DEBUG_NEW_LEAKS)
  361.  
  362.  
  363. #pragma mark -
  364. #pragma mark === operator delete ===
  365.  
  366. // ---------------------------------------------------------------------------
  367. //    • operator delete
  368. // ---------------------------------------------------------------------------
  369. //    Overridden to disable Spotlight memory checks.
  370.  
  371. void
  372. operator delete(
  373.     void*    ptr)
  374. {
  375. #if PP_Debug && PP_DebugNew_Support && (DEBUG_NEW >= DEBUG_NEW_BASIC)
  376.  
  377.     StSpotlightDisable_();
  378.     DebugNewDoFree(ptr, _std_operator_delete, false);
  379.  
  380. #else
  381.  
  382.     _std_operator_delete(ptr);
  383.  
  384. #endif
  385. }
  386.  
  387.  
  388. // ---------------------------------------------------------------------------
  389. //    • operator delete[]
  390. // ---------------------------------------------------------------------------
  391. //    Overridden to disable Spotlight memory checks.
  392.  
  393. void
  394. operator delete[](
  395.     void*    ptr)
  396. {
  397. #if PP_Debug && PP_DebugNew_Support && (DEBUG_NEW >= DEBUG_NEW_BASIC)
  398.  
  399.     StSpotlightDisable_();
  400.     DebugNewDoFree(ptr, _std_operator_array_delete, true);
  401.  
  402. #else
  403.  
  404.     _std_operator_array_delete(ptr);
  405.  
  406. #endif
  407. }
  408.  
  409.  
  410. #pragma mark -
  411. #pragma mark === new_handler ===
  412.  
  413. // ---------------------------------------------------------------------------
  414. //    • PP_NewHandler()
  415. // ---------------------------------------------------------------------------
  416. //    This is a new_handler function that attempts to free up memory
  417. //    when new fails to find enough memory. See section 18.4.2.2 of the C++
  418. //    standard, or section 14.4.5 in Stroustrup's 3rd edition.
  419. //
  420. //    It is not installed automatically. You must manually install it via
  421. //    set_new_handler().
  422.  
  423. #include <LGrowZone.h>
  424.  
  425. void PP_NewHandler() throw(PP_STD::bad_alloc);    // prototype
  426.  
  427. void PP_NewHandler() throw(PP_STD::bad_alloc)
  428. {
  429.         // Ask the GrowZone to free up memory. Since at this point we
  430.         // have no idea how much memory we need, consider any freed
  431.         // memory as a positive result and return so new can try again.
  432.         // If it failed to free any memory or there is no GrowZone at
  433.         // all, throw bad_alloc to signal the failure.
  434.         //
  435.         // This does assume that once DoGrowZone() has been called and
  436.         // if it returns a positive value, that subsequent calls to
  437.         // DoGrowZone() should fail to return a positive value (at least
  438.         // until after this allocation attempt has completed). Not only
  439.         // does this assumption affect this function, but the method
  440.         // used by new to allocate memory (malloc, my_alloc (New.cp),
  441.         // NewPtr, etc.) could potentially call into the system (NewPtr)
  442.         // and cause the GrowZone to again trigger. However the structuring
  443.         // of the implementation of new (at least in the Metrowerks runtimes,
  444.         // see New.cp) should utimately still end up in failure and none
  445.         // of this should truly be an issue.
  446.         //
  447.         // Besides, if you hit a situation like that, you're probably in
  448.         // deep kimchee anyways. ;-)
  449.         
  450.     LGrowZone*    theGZ = LGrowZone::GetGrowZone();
  451.     if (theGZ != nil) {
  452.         if (theGZ->DoGrowZone(max_Int32) > 0) {
  453.             return;
  454.         }
  455.     }
  456.     
  457.     throw PP_STD::bad_alloc();
  458. }